package fpzhan.plane.program.connect;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import fpzhan.plane.program.compose.AloneCodeBlockCompose;
import fpzhan.plane.program.compose.ComposeContent;
import fpzhan.plane.program.constant.ComposeType;
import fpzhan.plane.program.function.ChainCodeBlockFunction;
import fpzhan.plane.program.function.CodeBlockFunction;
import fpzhan.plane.program.function.LoopParamFunction;
import fpzhan.plane.program.manager.JsonKeyManager;
import fpzhan.plane.program.proxy.CodeBlockProxy;
import fpzhan.plane.program.struct.CodeBlockStruct;
import fpzhan.plane.program.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


public class LoopCodeBlockCompose extends AloneCodeBlockCompose {

    private ChainCodeBlockConnect child;

    private LoopParamFunction loopParamFlow;

//    private CollectFunction collect;

    private String loopElementKey;

    private String loopIndexKey;

    private String loopSizeKey;


//    public LoopCodeBlockCompose(ComposeContext composeContext, ChainCodeBlockConnect child, LoopParamFunction loopParamFlow, String loopElementKey, String loopIndexKey, String loopSizeKey) {
//        super(composeContext);
//        this.child = child;
//        this.loopParamFlow = loopParamFlow;
////        this.collect = collect;
//        this.loopElementKey = loopElementKey;
//        this.loopIndexKey = loopIndexKey;
//        this.loopSizeKey = loopSizeKey;
//    }

    public LoopCodeBlockCompose(ChainCodeBlockConnect child) {
        this.child = child;

        this.setComposeType(ComposeType.LOOP);
    }


    private CodeBlockFunction flow(ChainCodeBlockFunction loopCodeBlock){
        return param -> {
            Collection list = loopParamFlow.apply(param);
//            List<Param> result = new ArrayList<>();
            int size = list.size();
            Iterator iterator = list.iterator();
            int i = 0;
            Set preRun = new HashSet<>(param.keySet());
            while (iterator.hasNext()) {
                if (StringUtils.isNotEmpty(loopElementKey)) {
                    param.put(loopElementKey, iterator.next());
                }
                if (StringUtils.isNotEmpty(loopIndexKey)) {
                    param.put(loopIndexKey, i);
                }
                if (StringUtils.isNotEmpty(loopSizeKey)) {
                    param.put(loopSizeKey, size);
                }
                loopCodeBlock.apply(param);
//                result.add(one);
                i++;
            }
            Set afterRun = new HashSet<>(param.keySet());
            afterRun.removeAll(preRun);
            param.remove((String[])afterRun.toArray(new String[]{}));

            if (StringUtils.isNotEmpty(loopElementKey)) {
                param.remove(loopElementKey);
            }

        };
    }

    @Override
    public CodeBlockFunction compose(List<CodeBlockProxy> proxys, JSONObject proxyJson, CodeBlockStruct struct, JSONObject structJson, ComposeContent composeContent) throws Exception {
            JSONArray proxyArray = new JSONArray(new ArrayList<>());
            JSONArray structArray = new JSONArray(new ArrayList<>());
            CodeBlockFunction function = child.compose(proxyArray, structArray, composeContent);
            ChainCodeBlockFunction loopCodeBlock=param -> {};
            loopCodeBlock = loopCodeBlock.after(function);
            proxyJson.put(JsonKeyManager.getJsonKey().childLoopKey, proxyArray);
            if (structArray != null && structArray.size() > 0) structJson.put(JsonKeyManager.getJsonKey().childLoopKey, structArray);
            return super.compose(proxys, proxyJson, struct, structJson,   composeContent,flow(loopCodeBlock));
    }

    public ChainCodeBlockConnect getChild() {
        return child;
    }

    public void setLoopParamFlow(LoopParamFunction loopParamFlow) {
        this.loopParamFlow = loopParamFlow;
    }


//    public void setCollect(CollectFunction collect) {
//        this.collect = collect;
//    }

    public void setLoopElementKey(String loopElementKey) {
        this.loopElementKey = loopElementKey;
    }

    public void setLoopIndexKey(String loopIndexKey) {
        this.loopIndexKey = loopIndexKey;
    }

    public void setLoopSizeKey(String loopSizeKey) {
        this.loopSizeKey = loopSizeKey;
    }
}
